#include "flipview.h"
#include "animation.h"
#include "matrix.h"
#include <string.h>
#include <stdio.h>
#include <memory.h>
#include <stdlib.h>

#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xmlmemory.h>

typedef struct _FLIPVIEW
{
	UFO_View front, back;
	UFO_Animation rotate_front, rotate_back, z_front, z_back, alpha_front, alpha_back;
	int index;
}FLIPVIEW;

#define FLIPVIEW_FRONT 0
#define FLIPVIEW_BACK  1

#define FLIPVIEW_AXIS_Z 220
#define FLIPVIEW_ALPHA (0.1f)

#define FLIPVIEW_ANIMATION_DURATION 335

int internal_animation_callback(UFO_Animation animation, UFO_ANIMATION_STATE state, void* userdata)
{
	FLIPVIEW *pFlipView = userdata;
	if (pFlipView) {
		if (animation == pFlipView->rotate_front) {
			if (pFlipView->index/3 == FLIPVIEW_BACK) {
				pFlipView->index++;
				pFlipView->index %= 6;
			}
			else {
				UFO_Animation_Value value = {0};

				ufoViewSetMask(pFlipView->front, UFO_VIEW_BIT_HIDDEN, 1);
				ufoViewSetMask(pFlipView->back, UFO_VIEW_BIT_HIDDEN, 0);
				
				ufoViewSetAngle(pFlipView->back, UFO_PI/2);

				value.type = Animation_angle;
				value.angle = 0;
				ufoAnimationSetTimingFunction(pFlipView->rotate_back, TimingFunctionEaseOut);
				ufoAnimationSetToValue(pFlipView->rotate_back, value);
				ufoAnimationPlay(pFlipView->rotate_back);
			} 
		}
		else if (animation == pFlipView->z_front) {
			if (pFlipView->index/3 == FLIPVIEW_BACK) {
				pFlipView->index++;
				pFlipView->index %= 6;
			}
			else {
				UFO_Animation_Value value = {0};

				ufoViewSetMask(pFlipView->front, UFO_VIEW_BIT_HIDDEN, 1);
				ufoViewSetMask(pFlipView->back, UFO_VIEW_BIT_HIDDEN, 0);
				
				ufoViewSetZ(pFlipView->back, FLIPVIEW_AXIS_Z);

				value.type = Animation_axisZ;
				value.angle = 0;
				ufoAnimationSetTimingFunction(pFlipView->z_back, TimingFunctionEaseOut);
				ufoAnimationSetToValue(pFlipView->z_back, value);
				ufoAnimationPlay(pFlipView->z_back);
			} 
		}
		else if (animation == pFlipView->alpha_front) {
			if (pFlipView->index/3 == FLIPVIEW_BACK) {
				pFlipView->index++;
				pFlipView->index %= 6;
			}
			else {
				UFO_Animation_Value value = {0};

				ufoViewSetMask(pFlipView->front, UFO_VIEW_BIT_HIDDEN, 1);
				ufoViewSetMask(pFlipView->back, UFO_VIEW_BIT_HIDDEN, 0);

				//ufoViewSetColorMask(pFlipView->back, FLIPVIEW_ALPHA, FLIPVIEW_ALPHA, FLIPVIEW_ALPHA);

				value.type = Animation_colorMask;
				value.redMask = 1.0f;
				value.greenMask = 1.0f;
				value.blueMask = 1.0f;
				ufoAnimationSetTimingFunction(pFlipView->alpha_back, TimingFunctionEaseOut);
				ufoAnimationSetToValue(pFlipView->alpha_back, value);
				ufoAnimationPlay(pFlipView->alpha_back);
			} 
		}

		//#####################################################################

		else if (animation == pFlipView->rotate_back) {
			if (pFlipView->index/3 == FLIPVIEW_FRONT) {
				pFlipView->index++;
				pFlipView->index %= 6;
			}
			else {
				UFO_Animation_Value value = {0};

				ufoViewSetMask(pFlipView->back, UFO_VIEW_BIT_HIDDEN, 1);
				ufoViewSetMask(pFlipView->front, UFO_VIEW_BIT_HIDDEN, 0);

				ufoViewSetAngle(pFlipView->front, -UFO_PI/2);

				value.type = Animation_angle;
				value.angle = 0;
				ufoAnimationSetTimingFunction(pFlipView->rotate_front, TimingFunctionEaseOut);
				ufoAnimationSetToValue(pFlipView->rotate_front, value);
				ufoAnimationPlay(pFlipView->rotate_front);
			}
		}
		else if (animation == pFlipView->z_back) {
			if (pFlipView->index/3 == FLIPVIEW_FRONT) {
				pFlipView->index++;
				pFlipView->index %= 6;
			}
			else {
				UFO_Animation_Value value = {0};

				ufoViewSetMask(pFlipView->back, UFO_VIEW_BIT_HIDDEN, 1);
				ufoViewSetMask(pFlipView->front, UFO_VIEW_BIT_HIDDEN, 0);

				ufoViewSetZ(pFlipView->front, FLIPVIEW_AXIS_Z);

				value.type = Animation_axisZ;
				value.angle = 0;
				ufoAnimationSetTimingFunction(pFlipView->z_front, TimingFunctionEaseOut);
				ufoAnimationSetToValue(pFlipView->z_front, value);
				ufoAnimationPlay(pFlipView->z_front);
			}
		}
		else if (animation == pFlipView->alpha_back) {
			if (pFlipView->index/3 == FLIPVIEW_FRONT) {
				pFlipView->index++;
				pFlipView->index %= 6;
			}
			else {
				UFO_Animation_Value value = {0};

				ufoViewSetMask(pFlipView->back, UFO_VIEW_BIT_HIDDEN, 1);
				ufoViewSetMask(pFlipView->front, UFO_VIEW_BIT_HIDDEN, 0);

				//ufoViewSetColorMask(pFlipView->front, FLIPVIEW_ALPHA, FLIPVIEW_ALPHA, FLIPVIEW_ALPHA);

				value.type = Animation_colorMask;
				value.redMask = 1.0f;
				value.greenMask = 1.0f;
				value.blueMask = 1.0f;
				ufoAnimationSetTimingFunction(pFlipView->alpha_front, TimingFunctionEaseOut);
				ufoAnimationSetToValue(pFlipView->alpha_front, value);
				ufoAnimationPlay(pFlipView->alpha_front);
			}
		}
	}	
	return 1;
}

int ufoFlipViewSetFrontView(UFO_View view, UFO_View front)
{
	FLIPVIEW *pFlipView = ufoViewGetUserData(view);
	if (pFlipView) {
		pFlipView->front = front;
	}
	return 0;
}

int ufoFlipViewSetBackView(UFO_View view, UFO_View back)
{
	FLIPVIEW *pFlipView = ufoViewGetUserData(view);
	if (pFlipView) {
		pFlipView->back = back;
	}
	return 0;
}

int ufoFlipViewFlip(UFO_View view)
{
	FLIPVIEW *pFlipView = ufoViewGetUserData(view);
	if (pFlipView) {
		if (!pFlipView->rotate_front) {
			pFlipView->rotate_front = ufoAnimationCreate(pFlipView->front);
			ufoAnimationSetDuration(pFlipView->rotate_front, FLIPVIEW_ANIMATION_DURATION);
			ufoAnimationSetTimingFunction(pFlipView->rotate_front, TimingFunctionEaseIn);
			ufoAnimationSetCallback(pFlipView->rotate_front, internal_animation_callback, pFlipView);
		}
		if (!pFlipView->z_front) {
			pFlipView->z_front = ufoAnimationCreate(pFlipView->front);
			ufoAnimationSetDuration(pFlipView->z_front, FLIPVIEW_ANIMATION_DURATION);
			ufoAnimationSetTimingFunction(pFlipView->z_front, TimingFunctionEaseIn);
			ufoAnimationSetCallback(pFlipView->z_front, internal_animation_callback, pFlipView);
		}
		if (!pFlipView->alpha_front) {
			pFlipView->alpha_front = ufoAnimationCreate(pFlipView->front);
			ufoAnimationSetDuration(pFlipView->alpha_front, FLIPVIEW_ANIMATION_DURATION);
			ufoAnimationSetTimingFunction(pFlipView->alpha_front, TimingFunctionEaseIn);
			ufoAnimationSetCallback(pFlipView->alpha_front, internal_animation_callback, pFlipView);
		}

		if (!pFlipView->rotate_back) {
			pFlipView->rotate_back = ufoAnimationCreate(pFlipView->back);
			ufoAnimationSetDuration(pFlipView->rotate_back, FLIPVIEW_ANIMATION_DURATION);
			ufoAnimationSetTimingFunction(pFlipView->rotate_back, TimingFunctionEaseIn);
			ufoAnimationSetCallback(pFlipView->rotate_back, internal_animation_callback, pFlipView);
		}
		if (!pFlipView->z_back) {
			pFlipView->z_back = ufoAnimationCreate(pFlipView->back);
			ufoAnimationSetDuration(pFlipView->z_back, FLIPVIEW_ANIMATION_DURATION);
			ufoAnimationSetTimingFunction(pFlipView->z_back, TimingFunctionEaseIn);
			ufoAnimationSetCallback(pFlipView->z_back, internal_animation_callback, pFlipView);
		}
		if (!pFlipView->alpha_back) {
			pFlipView->alpha_back = ufoAnimationCreate(pFlipView->back);
			ufoAnimationSetDuration(pFlipView->alpha_back, FLIPVIEW_ANIMATION_DURATION);
			ufoAnimationSetTimingFunction(pFlipView->alpha_back, TimingFunctionEaseIn);
			ufoAnimationSetCallback(pFlipView->alpha_back, internal_animation_callback, pFlipView);
		}

		if (ufoAnimationGetState(pFlipView->rotate_front) == UFO_ANIMATION_PLAYING ||
			ufoAnimationGetState(pFlipView->z_front) == UFO_ANIMATION_PLAYING ||
			ufoAnimationGetState(pFlipView->rotate_back) == UFO_ANIMATION_PLAYING ||
			ufoAnimationGetState(pFlipView->z_back) == UFO_ANIMATION_PLAYING
			) {
				return 0;
		}

		if (pFlipView->index == FLIPVIEW_FRONT) {
			UFO_Animation_Value value = {0};

			value.type = Animation_angle;
			value.angle = -UFO_PI/2;
			ufoAnimationSetTimingFunction(pFlipView->rotate_front, TimingFunctionEaseIn);
			ufoAnimationSetToValue(pFlipView->rotate_front, value);
			ufoAnimationPlay(pFlipView->rotate_front);

			value.type = Animation_axisZ;
			value.z = FLIPVIEW_AXIS_Z;
			ufoAnimationSetTimingFunction(pFlipView->z_front, TimingFunctionEaseIn);
			ufoAnimationSetToValue(pFlipView->z_front, value);
			ufoAnimationPlay(pFlipView->z_front);

			value.type = Animation_colorMask;
			value.redMask = FLIPVIEW_ALPHA;
			value.greenMask = FLIPVIEW_ALPHA;
			value.blueMask = FLIPVIEW_ALPHA;
			ufoAnimationSetTimingFunction(pFlipView->alpha_front, TimingFunctionEaseIn);
			ufoAnimationSetToValue(pFlipView->alpha_front, value);
			ufoAnimationPlay(pFlipView->alpha_front);
		}
		else {
			UFO_Animation_Value value = {0};

			value.type = Animation_angle;
			value.angle = UFO_PI/2;
			ufoAnimationSetTimingFunction(pFlipView->rotate_back, TimingFunctionEaseIn);
			ufoAnimationSetToValue(pFlipView->rotate_back, value);
			ufoAnimationPlay(pFlipView->rotate_back);
            //ufoViewSetAngle(pFlipView->back, 0);
            
			value.type = Animation_axisZ;
			value.z = FLIPVIEW_AXIS_Z;
			ufoAnimationSetTimingFunction(pFlipView->z_back, TimingFunctionEaseIn);
			ufoAnimationSetToValue(pFlipView->z_back, value);
			ufoAnimationPlay(pFlipView->z_back);

			value.type = Animation_colorMask;
			value.redMask = FLIPVIEW_ALPHA;
			value.greenMask = FLIPVIEW_ALPHA;
			value.blueMask = FLIPVIEW_ALPHA;
			ufoAnimationSetTimingFunction(pFlipView->alpha_back, TimingFunctionEaseIn);
			ufoAnimationSetToValue(pFlipView->alpha_back, value);
			ufoAnimationPlay(pFlipView->alpha_back);
		}
	}
	return 0;
}

int default_flipView_proc(UFO_View view, int id, void* wParam, void* lParam)
{
	FLIPVIEW *pFlipView = ufoViewGetUserData(view);
	if (!pFlipView) {
		pFlipView = malloc(sizeof(FLIPVIEW));
		memset(pFlipView, 0, sizeof(FLIPVIEW));
		ufoViewSetUserData(view, pFlipView);
	}

	switch (id)
	{
	case MSG_CREATE:
		{
			ufoViewSetPerspective(view, 1);
		}
		break;

	case MSG_XML:
		{
			ufoViewDefaultProc(view, id, wParam, lParam);

			{
				xmlNodePtr node = wParam;
				xmlChar *frontView = xmlGetProp(node, (const xmlChar*)"frontView");
				xmlChar *backView = xmlGetProp(node, (const xmlChar*)"backView");
			
				if (frontView) {
					pFlipView->front = ufoViewGetFromId(view, frontView);
					if (pFlipView->front) {
						ufoViewSetAxis(pFlipView->front, AXIS_Y);
						ufoViewSetFovy(pFlipView->front, 25);
						//ufoViewSetMask(pFlipView->front, UFO_VIEW_BIT_HIDDEN, 1);
					}
					xmlFree(frontView);
				}

				if (backView) {
					pFlipView->back = ufoViewGetFromId(view, backView);
					if (pFlipView->back) {
						ufoViewSetAxis(pFlipView->back, AXIS_Y);
						ufoViewSetFovy(pFlipView->back, 25);
						//ufoViewSetAlpha(pFlipView->back, 0.2);
						//ufoViewSetAngle(pFlipView->back, 0.01);
						ufoViewSetMask(pFlipView->back, UFO_VIEW_BIT_HIDDEN, 1);
					}
					xmlFree(backView);
				}
			}
		}
		return 1;
	}

	return ufoViewDefaultProc(view, id, wParam, lParam);
}
